package com.das.a2048help

import android.app.Activity
import android.app.Application
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.PixelFormat
import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
import android.media.ImageReader
import android.media.projection.MediaProjection
import android.media.projection.MediaProjectionManager
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.os.ResultReceiver
import android.provider.MediaStore
import android.util.DisplayMetrics
import android.util.Log
import android.view.WindowManager
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.core.app.NotificationCompat
import com.das.a2048help.MainActivity.TessAPI
import com.google.android.flexbox.FlexboxLayout
import org.opencv.android.Utils
import org.opencv.core.Mat
import org.opencv.core.Point
import org.opencv.core.Rect
import org.opencv.core.Size
import org.opencv.imgproc.Imgproc
import java.io.File
import java.io.FileOutputStream
import java.io.OutputStream
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

class ForegroundService : Service() {
    private var mediaProjection: MediaProjection? = null
    private lateinit var virtualDisplay: VirtualDisplay
    private lateinit var windowManager: WindowManager


    companion object {
        private var TAG = "MediaProjectionService";
        private lateinit var mediaProjectionManager: MediaProjectionManager
        private lateinit var metrics: DisplayMetrics
        private lateinit var imageReader: ImageReader
        private var mImageAvailable = false

        private val regions = getRegions()
        private val game = Game2048()
        const val RESULT_CODE_SCREENSHOT = 1

        fun screenshot(context: Context, isSaveBitmap: Boolean): String? {
            if (!mImageAvailable) {
                Log.e(TAG, "screenshot: mImageAvailable is false");
                //showToast("截屏失败")
                return null;
            }

            val image = imageReader.acquireLatestImage()
            if (image != null) {
                val planes = image.planes
                val buffer = planes[0].buffer
                val pixelStride = planes[0].pixelStride
                val rowStride = planes[0].rowStride
                val rowPadding = rowStride - pixelStride * metrics.widthPixels

                val bitmap = Bitmap.createBitmap(
                    metrics.widthPixels + rowPadding / pixelStride,
                    metrics.heightPixels,
                    Bitmap.Config.ARGB_8888
                )
                bitmap.copyPixelsFromBuffer(buffer)

                if (isSaveBitmap) {
                    val fileName = generateFileName()
                    saveBitmapToFile(context, bitmap, fileName)
                }
                image.close()

                return getDirectionForOCR(bitmap)

            }
            return null;
        }

        private fun generateFileName(): String {
            val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault())
            return "screenshot_${dateFormat.format(Date())}.png"
        }


        private fun saveBitmapToFile(context: Context, bitmap: Bitmap, fileName: String) {
            val contentValues = ContentValues().apply {
                put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
                put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
                put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
            }

            val resolver = context.contentResolver
            val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
            if (uri != null) {
                var outputStream: OutputStream? = null
                try {
                    outputStream = resolver.openOutputStream(uri)
                    if (outputStream != null) {
                        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
                    }
                    outputStream?.flush()
                    Log.i("ForegroundService", "Screenshot saved to $uri")
                } catch (e: Exception) {
                    e.printStackTrace()
                    Log.e("ForegroundService", "Error saving screenshot: ${e.message}")
                } finally {
                    outputStream?.close()
                }
            }
        }

        private fun showToast(message: String) {
            Handler(Looper.getMainLooper()).post {
                Toast.makeText(MainActivity().applicationContext, message, Toast.LENGTH_SHORT)
                    .show()
            }
        }

        private fun getRegions(): MutableList<Rect> {
            val leftList = listOf(300, 494, 690, 884)
            val topList = listOf(963, 1177, 1382, 1590)
            val regions = mutableListOf<Rect>()
            for (top in topList) {
                for (left in leftList) {
                    regions.add(Rect(left, top, 36, 40))
                }
            }
            return regions
        }


        private fun getDirectionForOCR( bitmap: Bitmap):String {

            val tess = TessAPI.instance
            val ocrResult = mutableListOf<String>()
            val images = preprocessImage(bitmap)
            for (img in images) {
                tess.setImage(img)
                val text = tess.getUTF8Text();
                ocrResult.add(text)
            }

            val board = mutableListOf<Int>()
            for (str in ocrResult) {
                val num = str.toIntOrNull()
                if (num != null) {
                    board.add(num)
                } else {
                    board.add(0)
                }
            }

            Log.d("ForegroundService", "board：$board")
            val cBoard = game.toCBoard(board)
            val direction = game.nativeFindBestMove(cBoard)
            Log.d("ForegroundService", "推荐方向：$direction")

            return game.directionToStr(direction)
        }


        private fun preprocessImage(bitmap: Bitmap): MutableList<Bitmap> {
            val bitmaps = mutableListOf<Bitmap>()
            val mat = Mat()
            Utils.bitmapToMat(bitmap, mat)
            // 转换为灰度图像
            val grayMat = Mat()
            Imgproc.cvtColor(mat, grayMat, Imgproc.COLOR_RGBA2GRAY)

            for (roi in regions) {
                // 裁剪图像
                val croppedMat = Mat()
                Imgproc.getRectSubPix(
                    grayMat,
                    Size(roi.width.toDouble(), roi.height.toDouble()),
                    Point(roi.x + roi.width / 2.0, roi.y + roi.height / 2.0),
                    croppedMat
                )
                // 提高分辨率
                val resizedMat = Mat()
                val upscaleFactor = 2.0
                Imgproc.resize(
                    croppedMat,
                    resizedMat,
                    Size(croppedMat.cols() * upscaleFactor, croppedMat.rows() * upscaleFactor),
                    0.0,
                    0.0,
                    Imgproc.INTER_CUBIC
                )


                // 二值化处理
                val binaryMat = Mat()
                Imgproc.threshold(resizedMat, binaryMat, 128.0, 255.0, Imgproc.THRESH_BINARY_INV)
//            // 查找轮廓
//            val contours = mutableListOf<MatOfPoint>()
//            val hierarchy = Mat()
//            Imgproc.findContours(
//                binaryMat,
//                contours,
//                hierarchy,
//                Imgproc.RETR_EXTERNAL,
//                Imgproc.CHAIN_APPROX_SIMPLE
//            )
//
//            // 创建一个新的 Mat 对象，用于绘制填充后的图像
//            val blackMask = Mat.zeros(resizedMat.size(), CvType.CV_8UC1)
//
//            Imgproc.drawContours(blackMask, contours, -1, Scalar(255.0, 255.0, 255.0), -1) // 使用白色填充
//
//
//            val maskedMat = Mat()
//            Core.bitwise_and(resizedMat, resizedMat, maskedMat, blackMask)
//
//            //再次二值化去除数字周边杂项，这种必须保证数字再裁剪框中完整，不完整也会被轮廓消除
//            Imgproc.threshold(maskedMat, binaryMat, 128.0, 255.0, Imgproc.THRESH_BINARY_INV)

                // 将填充后的 Mat 对象转换回 Bitmap
                val resultBitmap =
                    Bitmap.createBitmap(binaryMat.cols(), binaryMat.rows(), Bitmap.Config.ARGB_8888)
                Utils.matToBitmap(binaryMat, resultBitmap)

                bitmaps.add(resultBitmap)
            }
            return bitmaps
        }
    }

    override fun onCreate() {
        super.onCreate()
        mediaProjectionManager =
            getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
        windowManager = getSystemService(WINDOW_SERVICE) as WindowManager

        // Create a notification channel for Android O and higher
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channelId = "ForegroundServiceChannel"
            val channelName = "Foreground Service Channel"
            val channel =
                NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT)
            val manager = getSystemService(NotificationManager::class.java)
            manager.createNotificationChannel(channel)
        }


        game.nativeInit()

    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val resultCode =
            intent?.getIntExtra("resultCode", Activity.RESULT_CANCELED) ?: Activity.RESULT_CANCELED
        val data = intent?.getParcelableExtra<Intent>("data")
        if (resultCode == Activity.RESULT_OK && data != null) {

            startForeground(1, createNotification())
            mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data)

            // Setup virtual display and image reader here
            metrics = DisplayMetrics()
            windowManager.defaultDisplay.getMetrics(metrics)
            val densityDpi = metrics.densityDpi

            imageReader = ImageReader.newInstance(
                metrics.widthPixels,
                metrics.heightPixels,
                PixelFormat.RGBA_8888,
                2
            )

            imageReader.setOnImageAvailableListener({
                mImageAvailable = true;
            }, null)

            virtualDisplay = mediaProjection!!.createVirtualDisplay(
                "ScreenCapture",
                metrics.widthPixels,
                metrics.heightPixels,
                densityDpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                imageReader.surface,
                null,
                null
            )


        } else {
            Toast.makeText(this, "Screen capture permission denied", Toast.LENGTH_SHORT).show()
        }

        return START_STICKY
    }


    private fun createNotification(): Notification {
        val channelId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            "ForegroundServiceChannel"
        } else {
            ""
        }

        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setContentTitle("Foreground Service")
            .setContentText("Screen capture in progress")
            //.setSmallIcon(R.drawable.ic_notification)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)

        return notificationBuilder.build()
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    override fun onDestroy() {
        super.onDestroy()
        virtualDisplay.release()
        mediaProjection?.stop()
    }
}